{
  "nbformat": 4,
  "nbformat_minor": 0,
  "metadata": {
    "colab": {
      "name": "PMF example.ipynb",
      "version": "0.3.2",
      "provenance": [],
      "private_outputs": true,
      "collapsed_sections": [],
      "toc_visible": true,
      "include_colab_link": true
    },
    "kernelspec": {
      "name": "python3",
      "display_name": "Python 3"
    }
  },
  "cells": [
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "view-in-github",
        "colab_type": "text"
      },
      "source": [
        "[View in Colaboratory](https://colab.research.google.com/github/ylongqi/openrec/blob/master/tutorials/PMF_example.ipynb)"
      ]
    },
    {
      "metadata": {
        "id": "UF5LN3pd78fh",
        "colab_type": "text"
      },
      "cell_type": "markdown",
      "source": [
        "<p align=\"center\">\n",
        "  <img src =\"https://recsys.acm.org/wp-content/uploads/2017/07/recsys-18-small.png\" height=\"40\" /> <font size=\"4\">Recsys 2018 Tutorial</font>\n",
        "</p>\n",
        "<p align=\"center\">\n",
        "  <font size=\"4\"><b>Modularizing Deep Neural Network-Inspired Recommendation Algorithms</b></font>\n",
        "</p>\n",
        "<p align=\"center\">\n",
        "  <font size=\"4\">Hands on: Customizing Deep YouTube Video Recommendation. PMF</font>\n",
        "</p>"
      ]
    },
    {
      "metadata": {
        "id": "xXV-a9jCQtvh",
        "colab_type": "text"
      },
      "cell_type": "markdown",
      "source": [
        "# Implement Probablistic Matrix Factorization \n",
        "\n",
        "In this example, we will walk you through an example of how to implement the `PMF` recommender using openrec.tf1.\n",
        "\n",
        "\n",
        "To implement  a model using OpenRec, you will need to first decide how this recommender should be decomposed into subgraphs, i.e., inputgraph, usergraph, itemgraph, interactiongraph and optimizergraph. For example, the training graph of `PMF` can be decomposed as follows.\n",
        "\n",
        "<p align=\"center\">\n",
        "  <img src =\"https://s3.amazonaws.com/cornell-tech-sdl-openrec/tutorials/pmf_module.png\" height=\"400\" />\n",
        "</p>\n",
        "\n",
        "\n",
        "* **inputgraph**: user item pairs and the groundtruth label.\n",
        "* **usergraph**: extract latent factor for users.\n",
        "* **itemgraph**: extract latent factors for items.\n",
        "* **interactiongraph**: uses Pointwise MSE to model user-item interactions.\n",
        "\n",
        "\n",
        "<p align=\"center\">\n",
        "  <img src =\"https://s3.amazonaws.com/cornell-tech-sdl-openrec/tutorials/pmf.png\" height=\"300\" />\n",
        "</p>"
      ]
    },
    {
      "metadata": {
        "id": "fx9f__-hL3C2",
        "colab_type": "text"
      },
      "cell_type": "markdown",
      "source": [
        "## Install OpenRec and download dataset"
      ]
    },
    {
      "metadata": {
        "id": "iCPtcmnDKsBH",
        "colab_type": "code",
        "colab": {}
      },
      "cell_type": "code",
      "source": [
        "!pip install openrec"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "metadata": {
        "id": "1Tel0pTqJWUE",
        "colab_type": "text"
      },
      "cell_type": "markdown",
      "source": [
        "# Your task \n",
        "-  fill in the placeholders in the implementation of the `PMF` function \n",
        "-  successfully run the experimental code with the recommender you just built. "
      ]
    },
    {
      "metadata": {
        "id": "DybVedLuNe_d",
        "colab_type": "code",
        "colab": {}
      },
      "cell_type": "code",
      "source": [
        "from openrec.tf1.recommenders import Recommender\n",
        "\n",
        "\n",
        "def Tutorial_PMF(batch_size, dim_user_embed, dim_item_embed, total_users, total_items, a=1.0, b=1.0, l2_reg=None,\n",
        "    init_model_dir=None, save_model_dir='Recommender/', train=True, serve=False):\n",
        "\n",
        "    rec = Recommender(init_model_dir=init_model_dir, save_model_dir=save_model_dir,\n",
        "                    train=train, serve=serve)\n",
        "\n",
        "    t = rec.traingraph\n",
        "    s = rec.servegraph\n",
        "\n",
        "    @t.inputgraph(outs=['user_id', 'item_id', 'label'])\n",
        "    def train_input_graph(subgraph):\n",
        "        subgraph['user_id'] = tf.placeholder(tf.int32, shape=[batch_size], name='user_id')\n",
        "        subgraph['item_id'] = tf.placeholder(tf.int32, shape=[batch_size], name='item_id')\n",
        "        subgraph['label'] = tf.placeholder(tf.float32, shape=[batch_size], name='label')\n",
        "        subgraph.register_global_input_mapping({'user_id': subgraph['user_id'],\n",
        "                                                'item_id': subgraph['item_id'],\n",
        "                                                'label': subgraph['label']})\n",
        "\n",
        "        \n",
        "    @s.inputgraph(outs=['user_id', 'item_id'])\n",
        "    def serve_input_graph(subgraph):\n",
        "        subgraph['user_id'] = tf.placeholder(tf.int32, shape=[None], name='user_id')\n",
        "        subgraph['item_id'] = tf.placeholder(tf.int32, shape=[None], name='item_id')\n",
        "        subgraph.register_global_input_mapping({'user_id': subgraph['user_id'],\n",
        "                                'item_id': subgraph['item_id']})\n",
        "\n",
        "        \n",
        "        \n",
        "    @t.usergraph(ins=['user_id'], outs=['user_vec'])\n",
        "    @s.usergraph(ins=['user_id'], outs=['user_vec'])\n",
        "    def user_graph(subgraph):\n",
        "        _, subgraph['user_vec'] = LatentFactor(l2_reg=l2_reg,\n",
        "                                       init='normal',\n",
        "                                       id_=subgraph['user_id'],\n",
        "                                       shape=[total_users, dim_user_embed],\n",
        "                                       subgraph=subgraph,\n",
        "                                       scope='user')\n",
        "\n",
        "        \n",
        "    @t.itemgraph(ins=['item_id'], outs=['item_vec', 'item_bias'])\n",
        "    @s.itemgraph(ins=[v3], outs=[v4, v5])\n",
        "    def item_graph(subgraph):\n",
        "        _, subgraph['item_vec'] = LatentFactor(l2_reg=l2_reg, init='normal', id_=subgraph['item_id'],\n",
        "                    shape=[total_items, dim_item_embed], subgraph=subgraph, scope='item_4')\n",
        "        _, subgraph['item_bias'] = LatentFactor(l2_reg=l2_reg, init='zero', id_=subgraph['item_id'],\n",
        "                    shape=[total_items, 1], subgraph=subgraph, scope='item_5')\n",
        "\n",
        "        \n",
        "        \n",
        "    @t.interactiongraph(ins=['user_vec', 'item_vec', 'item_bias', 'label'])\n",
        "    def interaction_graph(subgraph):\n",
        "        PointwiseMSE(user_vec=subgraph['user_vec'],\n",
        "                     item_vec=subgraph['item_vec'],\n",
        "                     item_bias=subgraph['item_bias'],\n",
        "                     label=subgraph['label'],\n",
        "                    a=a, b=b, sigmoid=False,\n",
        "                    train=True, subgraph=subgraph, scope='PointwiseMSE')\n",
        "\n",
        "      \n",
        "    @s.interactiongraph(ins=['user_vec', 'item_vec', 'item_bias'])\n",
        "    def serve_interaction_graph(subgraph):\n",
        "        PointwiseMSE(user_vec=subgraph['user_vec'],\n",
        "                     item_vec=subgraph['item_vec'],\n",
        "                     item_bias=subgraph['item_bias'],\n",
        "                     a=a, b=b, sigmoid=False,\n",
        "                    train=False, subgraph=subgraph, scope='PointwiseMSE')\n",
        "\n",
        "        \n",
        "    @t.optimizergraph\n",
        "    def optimizer_graph(subgraph):\n",
        "        losses = tf.add_n(subgraph.get_global_losses())\n",
        "        optimizer = tf.train.AdamOptimizer(learning_rate=0.001)\n",
        "        subgraph.register_global_operation(optimizer.minimize(losses))\n",
        "\n",
        "        \n",
        "    @t.connector\n",
        "    @s.connector\n",
        "    def connect(graph):\n",
        "        graph.usergraph['user_vec'] = graph.inputgraph['user_id']\n",
        "        graph.itemgraph['item_vec'] = graph.inputgraph['item_id']\n",
        "        graph.itemgraph['item_bias'] = graph.inputgraph['item_id']\n",
        "        graph.interactiongraph['user_vec'] = graph.usergraph['user_vec']\n",
        "        graph.interactiongraph['item_vec'] = graph.itemgraph['item_vec']\n",
        "        graph.interactiongraph['item_bias'] = graph.itemgraph['item_bias']\n",
        "\n",
        "    @t.connector.extend\n",
        "    def connect_label(graph):\n",
        "        graph.interactiongraph['label'] = graph.inputgraph['label']\n",
        "\n",
        "    return rec"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "metadata": {
        "id": "f9W89APf7A2X",
        "colab_type": "code",
        "colab": {}
      },
      "cell_type": "code",
      "source": [
        ""
      ],
      "execution_count": 0,
      "outputs": []
    }
  ]
}